#include "pch.h"
#include "Plugin.h"
#include "PluginLoader.h"




PluginLoader::PluginLoader(QString fileName)
	: m_library(fileName)
{
	m_library.load();

	if(!m_library.isLoaded())
	{
		QString error = m_library.errorString();
		BOOSTEXT_THROW(plugin_not_loaded("Can't load plugin: Unable to load the module"));
	}

	CreateFunction create;
	if(!(create = (CreateFunction)m_library.resolve("createPlugin")))
	{
		QString error = m_library.errorString();
		BOOSTEXT_THROW(plugin_not_loaded("The plugin doesn't export createPlugin()"));
	}

	NumberFunction number;
	if(!(number = (NumberFunction)m_library.resolve("numberOfPlugins")))
	{
		QString error = m_library.errorString();
		BOOSTEXT_THROW(plugin_not_loaded("The plugin doesn't export numberOfPlugins()"));
	}

	std::size_t num = number();
	if(num == 0)
		BOOSTEXT_THROW(plugin_not_loaded("The plugin doesn't implement any interface"));

	for(std::size_t i = 0; i < num; ++i)
	{
		Plugin::Ptr plugin = create(i);
		if(!plugin)
			BOOSTEXT_THROW(plugin_not_loaded("The plugin doesn't create a valid plugin"));

		// Plugins are disabled by default
		plugin->disable();
		m_plugins << plugin;
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////

PluginLoader::~PluginLoader()
{
	if(!canUnload())
		BOOSTEXT_THROW(boostext::critical_exception("An interface of the plugin is still being used and thus cannot be released"));

	foreach(Plugin::Ptr plugin, m_plugins)
	{
		plugin->disable();
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////




bool PluginLoader::canUnload() const
{
	foreach(const Plugin::Ptr& plugin, m_plugins)
	{
		if(plugin.use_count() != 1)
			return false;
	}

	return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




std::size_t PluginLoader::numPlugins() const
{
	return m_plugins.size();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

PluginLoader::iterator PluginLoader::begin()
{
	return m_plugins.begin();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

PluginLoader::iterator PluginLoader::end()
{
	return m_plugins.end();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

PluginLoader::const_iterator PluginLoader::begin() const
{
	return m_plugins.begin();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

PluginLoader::const_iterator PluginLoader::end() const
{
	return m_plugins.end();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

